#include <gtest/gtest.h>
#include <behaviortree_cpp_v3/behavior_tree.h>
#include <behaviortree_cpp_v3/bt_factory.h>
#include <logger/logger.h>

class AA: public BT::SyncActionNode
{
public:
    explicit AA(const std::string &name)
        : BT::SyncActionNode(name, {})
    {
        printf("1111\n");
    }
    ~AA()
    {
    }

    BT::NodeStatus tick() override
    {
        EASE_INFO("AA");
        return BT::NodeStatus::FAILURE;
    }
};

class BB: public BT::SyncActionNode
{
public:
    explicit BB(const std::string &name)
        : BT::SyncActionNode(name, {})
    {
    }
    ~BB()
    {
    }

    BT::NodeStatus tick() override
    {
        EASE_INFO("BB");
        return BT::NodeStatus::FAILURE;
    }
};

class CC: public BT::SyncActionNode
{
public:
    explicit CC(const std::string &name)
        : BT::SyncActionNode(name, {})
    {
    }

    BT::NodeStatus tick() override
    {
        EASE_INFO("CC");
        return BT::NodeStatus::FAILURE;
    }
};

TEST(test_class_sequence, behavior_tree_class)
{
    BT::BehaviorTreeFactory factory;
    factory.registerNodeType<AA>("AA");
    factory.registerNodeType<BB>("BB");
    factory.registerNodeType<CC>("CC");

    const char *xml_text = R"(
        <root>
            <BehaviorTree ID="MainTree">
                <Sequence>
                    <AA />
                    <BB />
                    <CC />
                </Sequence>
            </BehaviorTree>
        </root>
    )";

    BT::Tree tree = factory.createTreeFromText(xml_text);
    tree.tickOnce();

    EASE_INFO("done");
}

TEST(test_class_sequence_no_xml, behavior_tree_class)
{
    AA aa("");
    BB bb("");
    BT::SequenceNode sequence_node("");
    sequence_node.addChild(&aa);
    sequence_node.addChild(&bb);


    BT::NodeStatus status = sequence_node.executeTick();
    while (status == BT::NodeStatus::RUNNING)
    {
        status = sequence_node.executeTick();
    }
    EASE_INFO("result: %d", (int) status);
}

TEST(test_class_fallback, behavior_tree_class)
{
    BT::BehaviorTreeFactory factory;
    factory.registerNodeType<AA>("AA");
    factory.registerNodeType<BB>("BB");
    factory.registerNodeType<CC>("CC");

    const char *xml_text = R"(
        <root>
            <BehaviorTree ID="MainTree">
                <Fallback>
                    <AA />
                    <BB />
                    <CC />
                </Fallback>
            </BehaviorTree>
        </root>
    )";
    BT::Tree tree = factory.createTreeFromText(xml_text);
    tree.tickRoot();
}

TEST(behavior_tree_sequence_fallback_func, behavior_tree_class)
{
    BT::BehaviorTreeFactory factory;
    factory.registerNodeType<AA>("AA");
    factory.registerNodeType<BB>("BB");
    factory.registerNodeType<CC>("CC");

    const char *xml_text = R"(
        <root>
            <BehaviorTree ID="MainTree">
                <Sequence>
                    <Fallback>
                        <AA/>
                        <BB/>
                    </Fallback>
                    <CC/>
                </Sequence>
            </BehaviorTree>
        </root>
    )";

    BT::Tree tree = factory.createTreeFromText(xml_text);
    tree.tickRoot();
}

TEST(test_class_sequence_multiple, behavior_tree_class)
{
    BT::BehaviorTreeFactory factory;
    factory.registerNodeType<AA>("AA");
    factory.registerNodeType<BB>("BB");
    factory.registerNodeType<CC>("CC");

    const char *xml_text = R"(
        <root>
            <BehaviorTree ID="MainTree">
                <Sequence>
                    <AA />
                    <BB />
                    <CC />
                </Sequence>
            </BehaviorTree>
        </root>
    )";
    const char *xml_text_2 = R"(
        <root>
            <BehaviorTree ID="MainTree2">
                <Sequence>
                    <AA />
                    <BB />
                    <CC />
                </Sequence>
            </BehaviorTree>
        </root>
    )";

    factory.registerBehaviorTreeFromText(xml_text);
    factory.registerBehaviorTreeFromText(xml_text_2);
    auto tree1 = factory.createTree("MainTree");
    tree1.tickRoot();
    EASE_INFO("1 done");
    auto tree2 = factory.createTree("MainTree2");
    tree2.tickRoot();
    EASE_INFO("2 done");

    EASE_INFO("done");
}
